#ifndef AI9_LOGIC_2017_PPLAYERINFO_H
#define AI9_LOGIC_2017_PPLAYERINFO_H
#include <vector>
#include <map>
#include <string>
#include "json/json.h"
#include "network.hpp"
#include "const.h"
using namespace std;
namespace SDK
{
	struct Pos
	{
		int x, y;
		Pos(int x_ = -1, int y_ = -1);
		bool operator ==(const Pos &p)const;
		bool operator !=(const Pos &p)const;
		bool operator <(const Pos &p)const;
		Pos operator +(const Pos &p)const;
		Pos operator -(const Pos &p)const;
		int len2()const;
		double lenf()const;
		int dist2(const Pos &p)const;
		double distf(const Pos &p)const;
		string ToString()const;
	};//坐标

	//局面信息
	struct PPlayerInfo
	{
		struct Edge//传输管道
		{
			Pos source, target; //发起者与目标
			int LeftTime;//距离建造完成的时间(0为已经完成)
		};
		struct Event
		{
			EventType event;
            SkillType skillType;
			string sender, target;
            Pos pos;
            bool RemainSame;
            int energy;//如果是空投技能或设置传输的话此变量有用
            RobotType targetType;
		};
		struct Robot
		{
			struct Buff {
				BuffType type;
				int LeftTime;//剩余的时间(>0)
				double arg;//天灾的参数(伤害值)
			};
			struct Skill {
				SkillType type;
				int cd, max_cd;
				//计算每种技能使用消耗的能量(如果是空降技能包含第4个参数)
				static int Cost(SkillType skillType, int robotLevel, RobotType robotType);
			};
			int team;//所属阵营
			std::string id;//ID
			Pos pos;
			RobotType type;//机器人类型
			int level;//等级
			int attack;//攻击力
			int defense;//防御力
			int energy;//当前能量
            int attack_range;
			int hp;//生命值
			int max_hp;//最大生命值
			int efficiency;//能量采集效率
			int consumption;//养分消耗
			int transport_capacity;//结点传输容量
			int transport_range;//传输距离
			int outdeg;//最多连出的管道数
			vector<Buff>buffs;
			vector<Skill>skills;
			Buff* findBuff(BuffType type);
			Skill* findSkill(SkillType type);
			bool canUse(SkillType type);
		};
		struct HumanOrder//人工操作
		{
            HumanOrderType type;
            string info;//描述信息(控制台有效)
            Pos target;//鼠标事件、LocalButton事件、高亮事件有效
            int id;//按钮/键盘编号(Local、Global、按键独立，>=0)
			static HumanOrder fromJson(Json::Value root);
		};
		int round;//当前回合
		int team;//我方阵营(1 or 2)
		vector<Robot>robots;//机器人列表
		//注意选手不能改动robots，否则之前返回的Robot*可能失效
		vector<Edge>edges;//传输管道列表
		vector<HumanOrder> orders;//人工操作指令
        vector<Event> events;//上回合事件
		string JsonData;//PPlayerInfo的JSON版本
		const Robot* RobotAt(Pos pos) const;
        const Robot* RobotNamed(std::string id) const;
		vector<Edge> edgesFrom(Pos pos, bool withUnfinished = true) const;
		vector<Edge> edgesTo(Pos pos, bool withUnfinished = true) const;
        static vector<HumanOrder> readHumanOrders(vector<string> orders);
	};

	//玩家操作列表
	struct PCommand
	{
		struct Operation
		{
			OrderType type;//技能类型(如果不需要释放坐标的话那个变量就没有用)
			Pos source, target;//发起者坐标和释放坐标
			int energy;//如果是空投技能或设置传输的话此变量有用
			RobotType targetType;//如果是指定类型进化退化技能的话此变量有用
            bool RemainSame;//当操作为进退化时，true强制按原类型，false按指定类型
		};
		vector<Operation>cmds;
		void AddOrder(OrderType orderType, Pos source, Pos target = Pos(-1,-1), int energy = -1);
        void AddOrder(OrderType orderType, Pos source, RobotType robotType);
        void Evolve(Pos source);//按原类型进化一级
        void Vestigial(Pos source);//按原类型退化一级

		static Network net;
		/*
			测试是否存在传输方案，满足needs中记录的能量消耗。
			该函数可以用来测试是否存在方案，满足某些机器人释放某些技能的消耗。
			（因为能量传输阶段是在通常的技能阶段之前）
			info：传入PPlayerInfo。
			needs：表示每一个点需求的能量值，没有需求的点不必在map中。
			返回：true表示存在方案，false表示不存在。
				例如(1,2)点需要100能量，(3,4)点需要200能量，则可以写：
				map<Pos, int> needs;
				needs[Pos(1,2)]=100; needs[Pos(3,4)]=200;
				bool ok = Satisfiable(info, needs);
		*/
		static bool Satisfiable(const PPlayerInfo &info, const map<Pos, int> &needs);

		/*
			尝试尽可能向某个点供给能量，将方案添加到这个PCommand中。
			info：传入PPlayerInfo。
			target：要供给的点。
			needs（可选）：（意义同上）表示每一个点需求的能量值，没有需求的点不必在map中。
			如果指定了needs，则优先满足之，剩下的能量才会被尝试供给target。
			返回：被供给的能量总和，包括target原有的能量，target被供给的能量，和为needs保留的能量。
			如果needs本身不可能被满足（即Satisfiable会返回false），则也会添加一个方案，但这个方案不会供给target，只会尽可能满足needs。
		*/
		int AddAutoTransfer(const PPlayerInfo &info, Pos target, const map<Pos, int> &needs = map<Pos, int>());

		/*
			尝试向某一些点供给能量，将方案添加到这个PCommand中。每个点的优先级可以不同。
			info：传入PPlayerInfo。
			weights：要供给的点的优先级。优先级越大，供给的能量越多（近似成正比）。
				例如，(1,2)点的优先级为2，(3,4)点的优先级为3，则应调用：
				map<Pos, int> weights;
				weights[Pos(1,2)]=2; weights[Pos(3,4)]=3;
				AddAutoTransfer(info, weights);
				假设场上除了这两个机器人以外只有一个机器人，它有500能量，且向这两个点都有传输线，则(1,2)将获得200能量，(3,4)将获得300能量。
			needs（可选）：（意义同上）表示每一个点需求的能量值，没有需求的点不必在map中。
			如果指定了needs，则优先满足之，剩下的能量才会被尝试供给weights中的点。
			返回：被供给的能量总和，包括weights中每个点原有的能量，weights中的点被供给的能量，和为needs保留的能量。
			如果needs本身不可能被满足（即Satisfiable会返回false），则也会添加一个方案，但这个方案不会供给weights中的点，只会尽可能满足needs。
		*/
		int AddAutoTransfer(const PPlayerInfo &info, const map<Pos, int> &weights, const map<Pos, int> &needs = map<Pos, int>());

		/*
			这两个函数是上面函数调用的helper函数，不必理会。
		*/
		static bool _AddAutoTransfer_Helper_Flow(const PPlayerInfo &info, const map<Pos, int> &weights, double ex, const std::vector<Pos> &poss, const map<Pos, int> &needs);
		static int _AddAutoTransfer_Helper_Sum(const map<Pos, int> &weights, double ex);
	};

	//反馈给播放器的信息
	struct PShowInfo
	{
		struct ShowInfo
		{
			ShowInfoType type;
			Pos target;
			int radius;//展示圆操作有效
			string info;//展示字符串有效
            Json::Value toJson();
		};
		vector<ShowInfo>cmds;
		void ShowString(string info);
		void ShowCircle(Pos center, int radius);
		void PosFlash(Pos target);
		void SelectGrid(Pos target);
		void DeselectGrid();
		void Surrender();
		void merge(PShowInfo & pShowInfo);
        Json::Value toJson();
	};
}

#endif //AI9_LOGIC_2017_PPLAYERINFO_H
